﻿/**	archive.hpp
 *	----	Create Time Stamp	--2009-01-25 14:04:49--
 *------------------------------------------------------------------------------
 *	Mean	:
 *	Author	:Nick Shallery	(nicknide@gmail.com)
 *	Version	:1.0.5.9	(2009-08-28 23:15:33)
 *------------------------------------------------------------------------------
**/	/*YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.*/

#if			!defined(__LOLIX_TOY__ARCHIVE__NICK__K_IN_G__)
#define		__LOLIX_TOY__ARCHIVE__NICK__K_IN_G__
//==============================================================================
//--------------------------------------------------------------------------

#if			!defined(__LOLIX__LOLI__FILE__K_IN_G__)
	#include	"../loli/file.h"
#endif	//	!defined(__LOLIX__LOLI__FILE__K_IN_G__)

namespace lolix{namespace toy{
	template<typename _Teh, typename _TPmap>
	class	archive_base;
	class	archive_error_handle_no_throw;
	typedef	archive_base<archive_error_handle_no_throw, void>	archive_no_throw;
}}


template<typename _Teh>
class lolix::toy::archive_base<_Teh, void>
{
	typedef		archive_base<_Teh, void>	this_type;
public:
	typedef	loli::file_flow file_type;
	typedef	_Teh		error_handle_type;
	typedef	void		property_map_type;

	LOLIX_INLINE_CALL	archive_base<_Teh, void>(file_type* fs): _fs(fs)
	{ _fs->inc_ref(); };
	LOLIX_INLINE_CALL	archive_base<_Teh, void>(file_type* fs, const _Teh& eh): _fs(fs), _eh(eh)
	{ _fs->inc_ref(); };
	LOLIX_INLINE_CALL	archive_base<_Teh, void>(const archive_base<_Teh, void>& other)
		: _fs(other._fs)
		, _eh(other._eh)
	{
		_fs->inc_ref();
	}
	LOLIX_INLINE_CALL	~archive_base<_Teh, void>(void)
	{
		_fs->release();
	}

	LOLIX_INLINE_CALL	archive_base<_Teh, void>& operator = (const archive_base<_Teh, void>& other)
	{
		_fs->release();
		(_fs = other._fs)->inc_ref();
		_eh = other._eh;
		return *this;
	}

	LOLIX_INLINE_CALL	error_handle_type&	get_eh(void)
	{
		return _eh;
	}

	LOLIX_INLINE_CALL	const error_handle_type&	get_eh(void)const
	{
		return _eh;
	}

	LOLIX_INLINE_CALL	loli::file_stream*	get_fs(void)
	{
		return _fs;
	}

	LOLIX_INLINE_CALL	loli::file_stream const*	get_fs(void)const
	{
		return _fs;
	}

	LOLIX_INLINE_CALL	this_type&	touch(void* buf, size_type buf_size)
	{
		if ( !_eh )
			return *this;

		LOLIX_RETNV rtv;
		const size_type query_size = buf_size;
		if ( LOLIX_IS_ERROR(rtv = _fs->touch(buf, &buf_size, 0)) || query_size != buf_size )
			_eh.handle_touch_error(_fs, query_size, buf_size, rtv);
		return *this;
	}

	LOLIX_INLINE_CALL	this_type&	read(void* buf, size_type buf_size)
	{
		if ( !_eh )
			return *this;

		LOLIX_RETNV rtv;
		const size_type query_size = buf_size;
		if ( LOLIX_IS_ERROR(rtv = _fs->read(buf, &buf_size, 0)) || query_size != buf_size )
			_eh.handle_read_error(_fs, query_size, buf_size, rtv);
		return *this;
	}

	LOLIX_INLINE_CALL	this_type&	write(const void* buf, size_type buf_size)
	{
		if ( !_eh )
			return *this;

		LOLIX_RETNV rtv;
		const size_type query_size = buf_size;
		if ( LOLIX_IS_ERROR(rtv = _fs->write(buf, &buf_size, 0)) || query_size != buf_size )
			_eh.handle_write_error(_fs, query_size, buf_size, rtv);
		return *this;
	}

private:
	file_type*	_fs;
	_Teh				_eh;
};


template<typename _Teh, typename _TPmap>
class	lolix::toy::archive_base
	: private archive_base<_Teh, void>
{
	_TPmap	_pmap;
	typedef	archive_base<_Teh, _TPmap>	this_type;
	typedef	archive_base<_Teh, void>	base_type;
public:
	typedef	typename	base_type::error_handle_type	error_handle_type;
	typedef	_TPmap										property_map_type;
	typedef	typename	_TPmap::key_type				key_type;
	typedef	typename	_TPmap::mapped_type				value_type;

	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(loli::file_stream* fs): base_type(fs){}
	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(loli::file_stream* fs, const _Teh& eh): base_type(fs, eh){}
	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(archive_base<_Teh, _TPmap> const& o): base_type(o), _pmap(o._pmap){}

	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(_TPmap const& pmap):_pmap(pmap){}
	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(loli::file_stream* fs, _TPmap const& pmap): base_type(fs), _pmap(pmap){}

	template<typename _Tmap>
	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(loli::file_stream* fs, _Tmap& pmap): base_type(fs), _pmap(pmap){}

	template<typename _Tmap0, typename _Tmap1>
	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>(loli::file_stream* fs, _Tmap0& pmap0, _Tmap1 pmap1): base_type(fs), _pmap(pmap0, pmap1){}

	template<typename _Th, typename _Tmap>
	LOLIX_INLINE_CALL	archive_base<_Teh, _TPmap>& operator = (const archive_base<_Th, _Tmap>& o)
	{
		base_type::operator = (o);
		_pmap = o._pmap;
		return *this;
	}

	using base_type::get_eh;
	using base_type::get_fs;

	this_type&	touch(void* buf, size_type buf_size)
	{
		base_type::touch(buf, buf_size);
		return *this;
	}

	this_type&	read(void* buf, size_type buf_size)
	{
		base_type::read(buf, buf_size);
		return *this;
	}
	this_type&	write(const void* buf, size_type buf_size)
	{
		base_type::write(buf, buf_size);
		return *this;
	}

	LOLIX_INLINE_CALL	bool	get_value(value_type const* val, key_type const& key)const
	{
		property_map_type::const_iterator iter = _pmap.find(key);
		if ( iter == _pmap.end() )
			return false;
		*val = iter->second;
		return true;
	}

	LOLIX_INLINE_CALL	void	set_value(key_type const& key, value_type const& val)
	{
		_pmap[key] = val;
	}

	LOLIX_INLINE_CALL	bool	insert_value(key_type const& key, value_type const& val)
	{
		return _pmap.insert(property_map_type::value_type(key, val)).second;
	}

	LOLIX_INLINE_CALL	bool	update_value(key_type const& key, value_type const& val)
	{
		property_map_type::iterator iter = _pmap.find(key);
		if ( iter == _pmap.end() )
			return false;
		iter->second = val;
		return true;
	}

	property_map_type const&	get_map(void)const
	{
		return _pmap;
	}

	property_map_type&			get_map(void)
	{
		return _pmap;
	}
};



class lolix::toy::archive_error_handle_no_throw
{
	LOLIX_RETNV	_err;
	struct	_bool_struct{};
	typedef	loli::file_flow	file_type;
public:
	archive_error_handle_no_throw(void)
		: _err(LOLIX_RETNV_OK){}

	LOLIX_RETNV	err(void)const
	{
		return _err;
	}

	operator _bool_struct* (void)const
	{
		return LOLIX_IS_ERROR(_err)?(_bool_struct*)0:(_bool_struct*)1;
	}

	void	handle_touch_error(file_type*, size_type /*query_size*/, size_type /*finish_size*/, LOLIX_RETNV rtv)
	{
		_err = LOLIX_IS_ERROR(rtv)?rtv:LOLIX_ERROR_FILE;
	}
	void	handle_read_error(file_type*, size_type /*query_size*/, size_type /*finish_size*/, LOLIX_RETNV rtv)
	{
		_err = LOLIX_IS_ERROR(rtv)?rtv:LOLIX_ERROR_FILE;
	}
	void	handle_write_error(file_type*, size_type /*query_size*/, size_type /*finish_size*/, LOLIX_RETNV rtv)
	{
		_err = LOLIX_IS_ERROR(rtv)?rtv:LOLIX_ERROR_FILE;
	}
};



//--------------------------------------------------------------------------
//==============================================================================
#endif	//	!defined(__LOLIX_TOY__ARCHIVE__NICK__K_IN_G__)
